{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Goodies of the [Python Standard Library](https://docs.python.org/3/library/#the-python-standard-library)\n",
    "The Python Standard Libary is part of your Python installation. It contains a wide range of packages which may be helpful while building your Python masterpieces. This notebook lists some of the commonly used packages and their main functionalities."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [`datetime`](https://docs.python.org/3/library/datetime.html#module-datetime) for working with dates and times"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import datetime as dt\n",
    "\n",
    "local_now = dt.datetime.now()\n",
    "print(f\"local now: {local_now}\")\n",
    "\n",
    "utc_now = dt.datetime.utcnow()\n",
    "print(f\"utc now: {utc_now}\")\n",
    "\n",
    "# You can access any value separately:\n",
    "print(\n",
    "    f\"{local_now.year} {local_now.month} {local_now.day} {local_now.hour} {local_now.minute} {local_now.second}\"\n",
    ")\n",
    "\n",
    "print(f\"date: {local_now.date()}\")\n",
    "print(f\"time: {local_now.time()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `strftime()`\n",
    "For string formatting the `datetime`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "formatted1 = local_now.strftime(\"%Y/%m/%d-%H:%M:%S\")\n",
    "print(formatted1)\n",
    "\n",
    "formatted2 = local_now.strftime(\"date: %Y-%m-%d time:%H:%M:%S\")\n",
    "print(formatted2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `strptime()`\n",
    "For converting a datetime string into a `datetime` object "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dt = dt.datetime.strptime(\"2000-01-01 10:00:00\", \"%Y-%m-%d %H:%M:%S\")\n",
    "print(f\"my_dt: {my_dt}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [`timedelta`](https://docs.python.org/3/library/datetime.html#timedelta-objects)\n",
    "For working with time difference."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tomorrow = local_now + dt.timedelta(days=1)\n",
    "print(f\"tomorrow this time: {tomorrow}\")\n",
    "\n",
    "delta = tomorrow - local_now\n",
    "print(f\"tomorrow - now = {delta}\")\n",
    "print(f\"days: {delta.days}, seconds: {delta.seconds}\")\n",
    "print(f\"total seconds: {delta.total_seconds()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Working with timezones"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import datetime as dt\n",
    "from zoneinfo import ZoneInfo\n",
    "\n",
    "naive_utc_now = dt.datetime.utcnow()\n",
    "print(f\"naive utc now: {naive_utc_now}, tzinfo: {naive_utc_now.tzinfo}\")\n",
    "\n",
    "# Localizing naive datetimes\n",
    "UTC_TZ = ZoneInfo(\"UTC\")\n",
    "utc_now = naive_utc_now.replace(tzinfo=UTC_TZ)\n",
    "print(f\"utc now: {utc_now}, tzinfo: {utc_now.tzinfo}\")\n",
    "\n",
    "# Converting localized datetimes to different timezone\n",
    "PARIS_TZ = ZoneInfo(\"Europe/Paris\")\n",
    "paris_now = utc_now.astimezone(PARIS_TZ)\n",
    "print(f\"Paris: {paris_now}, tzinfo: {paris_now.tzinfo}\")\n",
    "\n",
    "NEW_YORK_TZ = ZoneInfo(\"America/New_York\")\n",
    "ny_now = utc_now.astimezone(NEW_YORK_TZ)\n",
    "print(f\"New York: {ny_now}, tzinfo: {ny_now.tzinfo}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**NOTE**: If your project uses datetimes heavily, you may want to take a look at external libraries, such as [Pendulum](https://pendulum.eustace.io/docs/) and [Maya](https://github.com/kennethreitz/maya), which make working with datetimes easier for certain use cases."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [`logging`](https://docs.python.org/3/library/logging.html#module-logging)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "\n",
    "# Handy way for getting a dedicated logger for every module separately\n",
    "logger = logging.getLogger(__name__)\n",
    "logger.setLevel(logging.WARNING)\n",
    "\n",
    "logger.debug(\"This is debug\")\n",
    "logger.info(\"This is info\")\n",
    "logger.warning(\"This is warning\")\n",
    "logger.error(\"This is error\")\n",
    "logger.critical(\"This is critical\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Logging expections\n",
    "There's a neat `exception` function in `logging` module which will automatically log the stack trace in addition to user defined log entry. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    path_calculation = 1 / 0\n",
    "except ZeroDivisionError:\n",
    "    logging.exception(\"All went south in my calculation\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Formatting log entries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "\n",
    "# This is only required for Jupyter notebook environment\n",
    "from importlib import reload\n",
    "\n",
    "reload(logging)\n",
    "\n",
    "my_format = \"%(asctime)s | %(name)-12s | %(levelname)-10s | %(message)s\"\n",
    "logging.basicConfig(format=my_format)\n",
    "\n",
    "logger = logging.getLogger(\"MyLogger\")\n",
    "\n",
    "logger.warning(\"Something bad is going to happen\")\n",
    "logger.error(\"Uups, it already happened\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Logging to a file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "from pathlib import Path\n",
    "\n",
    "# This is only required for Jupyter notebook environment\n",
    "from importlib import reload\n",
    "\n",
    "reload(logging)\n",
    "\n",
    "logger = logging.getLogger(\"MyFileLogger\")\n",
    "\n",
    "# Let's define a file_handler for our logger\n",
    "log_path = Path.cwd() / \"my_log.txt\"\n",
    "file_handler = logging.FileHandler(log_path)\n",
    "\n",
    "# And a nice format\n",
    "formatter = logging.Formatter(\n",
    "    \"%(asctime)s | %(name)-12s | %(levelname)-10s | %(message)s\"\n",
    ")\n",
    "file_handler.setFormatter(formatter)\n",
    "\n",
    "logger.addHandler(file_handler)\n",
    "\n",
    "# If you want to see it also in the console, add another handler for it\n",
    "# logger.addHandler(logging.StreamHandler())\n",
    "\n",
    "logger.warning(\"Oops something is going to happen\")\n",
    "logger.error(\"John Doe visits our place\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [`random`](https://docs.python.org/3/library/random.html) for random number generation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "\n",
    "rand_int = random.randint(1, 100)\n",
    "print(f\"random integer between 1-100: {rand_int}\")\n",
    "\n",
    "rand = random.random()\n",
    "print(f\"random float between 0-1: {rand}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you need pseudo random numbers, you can set the `seed` for random. This will reproduce the output (try running the cell multiple times):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "\n",
    "random.seed(5)  # Setting the seed\n",
    "\n",
    "# Let's print 10 random numbers\n",
    "for _ in range(10):\n",
    "    print(random.random())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [`re`](https://docs.python.org/3/library/re.html#module-re) for regular expressions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Searching occurences"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "\n",
    "secret_code = \"qwret 8sfg12f5 fd09f_df\"\n",
    "# \"r\" at the beginning means raw format, use it with regular expression patterns\n",
    "search_pattern = r\"(g12)\"\n",
    "\n",
    "match = re.search(search_pattern, secret_code)\n",
    "print(f\"match: {match}\")\n",
    "print(f\"match.group(): {match.group()}\")\n",
    "\n",
    "numbers_pattern = r\"[0-9]\"\n",
    "numbers_match = re.findall(numbers_pattern, secret_code)\n",
    "print(f\"numbers: {numbers_match}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Variable validation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "\n",
    "\n",
    "def validate_only_lower_case_letters(to_validate):\n",
    "    pattern = r\"^[a-z]+$\"\n",
    "    return bool(re.match(pattern, to_validate))\n",
    "\n",
    "\n",
    "print(validate_only_lower_case_letters(\"thisshouldbeok\"))\n",
    "print(validate_only_lower_case_letters(\"thisshould notbeok\"))\n",
    "print(validate_only_lower_case_letters(\"Thisshouldnotbeok\"))\n",
    "print(validate_only_lower_case_letters(\"thisshouldnotbeok1\"))\n",
    "print(validate_only_lower_case_letters(\"\"))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
